#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<unordered_map>
#include<functional>
#include "Sock.hpp"
#include "Log.hpp"
#include "Epoller.hpp"
#include "Until.hpp"
#include "Protocol.hpp"

//基于Reactor模式，编写一个充分读取和写入的，Epoll(ET)的server

//定义套接字和接收数据和发送数据

class connection;
class TcpServer;

using func_t = std::function<int(connection*)>;

using callback_t = std::function<int(connection*,std::string&)>;

class connection
{
public:
    int sock_;
    TcpServer* R;
    std::string inbuffer;
    std::string outbuffer;

    //读取回调，套接字就绪，输入数据到inbuffer；
    func_t recver_;
    //send 回调
    func_t sender_;
    //异常回调
    func_t excepter_;
public:
    //recv_back
    connection(int sock, TcpServer* r):sock_(sock),R(r)
    {};
    //设置回调函数
    void SetRecver(func_t recver) {recver_ = recver;};
    void SetSender(func_t sender) {sender_ = sender;};
    void SetExpter(func_t excepter) {excepter_ = excepter;};
    ~connection(){};
};

//整合网络和epoll 根据网络情况 派发IO事件
class TcpServer
{   
public:
    TcpServer(int port = 8080, callback_t cb):cb_(cb)
    {
        revs = new struct epoll_event[revs_num];
        //网络功能
        listensock = Sock::Socket();
        Util::SetNonBlock(listensock);
        Sock::Bind(listensock,port);
        Sock::Listen(listensock);
        //多路转接
        epfd_ = Epoller::CreateEpoller();

        //添加listensock到epoll中
        if(!Epoller::AddEvent(epfd_,listensock,EPOLLIN|EPOLLET))
        {
            logMessage(FATAL,"添加事件错误\n");
        };
        connection* conn= new connection(listensock,this);
        // //设置接收回调函数
        // conn->SetRecver(std::bind(&TcpServer::Accepter,this,std::placeholders::_1));
        //底层数据就绪，处理。
        connects_.insert(std::make_pair(listensock, conn));
    };

    int Accepter(connection* conn)
    {
        std::string clientip;
        uint16_t clientport;
        //从server sock 获取连接上的客户端的sock
        int sockfd = Sock::Accept(conn->sock_,&clientip,&clientport);
        if(sockfd < 0)
        {
            logMessage(WARNING,"accept error %s : %d\n",errno, strerror(errno));
            return 0;
        }
        //建立与客户端的链接通路，创建新的connect对象。
        AddConection(sockfd,EPOLLIN | EPOLLOUT);

        logMessage(DEBUG,"get new link = %d",sockfd);

        return 0;
    }

    //读取方法
    int TcpRecver(connection* conn)
    {
        // XXXXX\3XXXXX\3 报文格式
        //存在粘包问题
        // char buffer[1024];
        // size_t s = recv(conn->sock_,buffer,sizeof(buffer),0);

        while(true)
        {
            char buffer[1024];
            //阻塞等待 直到数据到来，
            //设置成非阻塞，返回值为-1，需业务方面考虑继续等待 还是结束此次连接
            size_t s = recv(conn->sock_,buffer,sizeof(buffer),0);
            if(s > 0)
            {
                buffer[s] = 0;
                conn->inbuffer += buffer;
            }
            else if( s == 0)
            {
                conn->excepter_(conn);
                logMessage(DEBUG, "client quit\n");
                break;
            }
            else
            {
                //error 
                conn->excepter_(conn);
                logMessage(DEBUG,"client error\n");
                break;
            }

        }
        //本轮读取完毕，
        std::vector<std::string> result;
        //解析报文
        PackageSplit(conn->inbuffer, &result);
        for(auto &message : result)
        {
            cb_(conn,message);
        }
        return 0;
    }
    //发送方法
    int TcpSend(connection* conn)
    {
        while(true)
        {
            int n = send(conn->sock_,conn->outbuffer.c_str(),conn->outbuffer.size(),0); 
            if(n > 0)
            {
                logMessage(DEBUG,"send %d bit",n);
                //移除已经发送出去的数据
                conn->outbuffer.erase(0,n);
            }
            else
            {
                //失败了,重发
                if(errno = EINTR) continue;
                //发送数据完成 buffer 不一定为null
                else if(errno == EAGAIN || errno == EWOULDBLOCK) break;
                else
                {
                    //异常
                    conn->excepter_(conn);
                    logMessage(DEBUG,"send error %d:%s\n",errno, strerror(errno));
                    break;
                }
            }
        } 

        //发送完毕之后 是否需要关心sock的读写
        //out 为空 关心读事件
        // if(conn->outbuffer.empty()) EnableReadWrite(conn->sock_,true,false);
        // else EnableReadWrite(conn->sock_,true,true);
        return 0;
    }
    //异常处理
    int TcpExcepter(connection* conn)
    {
        // 所有的服务器异常，都会被归类到这里
        // 坑：一定要先从epoll中移除，然后再关闭fd

        //服务器异常处理函数,所有异常都走这块
        if(!IsExist(conn->sock_)) return -1;
        //移除event事件
        Epoller::DeleteEvent(epfd_, conn->sock_);
        logMessage(DEBUG,"remove epoll event\n");
        //关闭套接字
        close(conn->sock_);
        logMessage(DEBUG,"close socket\n");
        //移除key节点 对应的 value
        delete connects_[conn->sock_];
        logMessage(DEBUG,"delete connection value\n");
        //移除key节点
        connects_.erase(conn->sock_);
        logMessage(DEBUG,"delete map connect\n");

        return 0;
    }


    //添加连接 1，先添加事件到epoll中
    void AddConection(int sockfd, uint32_t event)
    {
        if(event & EPOLLET)
        {
            Util::SetNonBlock(sockfd);
        }
        //添加sockfd到epoll中
        Epoller::AddEvent(epfd_,sockfd,event);

        connection* conn = new connection(sockfd,this);
        //注册回调
        conn->SetRecver(std::bind(&TcpServer::TcpRecver,this, std::placeholders::_1));
        conn->SetSender(std::bind(&TcpServer::TcpSend,this, std::placeholders::_1));
        conn->SetExpter(std::bind(&TcpServer::TcpExcepter,this,std::placeholders::_1));

        //将sockfd添加到connection中
        connects_.insert(std::make_pair(sockfd, conn));
        logMessage(DEBUG,"添加新链接connection成功 %d",sockfd);
    }


    //判断sock是否还有connection
    bool IsExist(int sock)
    {
        auto iter = connects_.find(sock);
        if(iter == connects_.end())
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    // 打开或者关闭对于特定socket是否要关心读或者写
    //EnableReadWrite(sock, true, false);
    //EnableReadWrite(sock, true, true);
    void EnableReadWrite(int sock, bool readable, bool writeadble)
    {
        uint32_t event = 0;

        event |= (readable ? EPOLLIN : 0);
        event |= (writeadble ? EPOLLOUT : 0);

        //修改epoll句柄 
        Epoller::ModEvent(epfd_,sock,event);
    }

    void Dispather()
    {
        int n = Epoller::LoopOnce(epfd_, revs, revs_num);
        for(int i = 0; i < n; i++)
        {
            int sock = revs[i].data.fd;
            uint32_t revent = revs[i].events;
            //读事件就绪
            if(revent & EPOLLIN)
            {   
                if(IsExist(sock) && connects_[sock]->recver_)
                {
                    connects_[sock]->recver_(connects_[sock]);
                }
            }
            if(IsExist(sock) && revent &EPOLLOUT)
            {
                if(connects_[sock]->sender_)
                {
                    connects_[sock]->sender_(connects_[sock]);
                }
            }
        }

    }

    void Run()
    {
        while(true)
        {
            Dispather();
        }
    }
    
    ~TcpServer()
    {
        if(listensock != -1)
        {
            close(listensock);
        }
        if(epfd_ != -1)
        {
            close(epfd_);
        }
        delete [] revs;
    };
private:

    static const int revs_num = 64;
    // 1，网络socket
    int listensock;
    // 2, epoll 派发事件
    int epfd_;
    // 3,将epoll和上层代码结合
    std::unordered_map<int, connection*> connects_;
    // 4,就绪事件列表
    struct epoll_event* revs;
    //设置完整报文的处理方法
    callback_t cb_;
};